package cn.zjh.user.service.service.impl;

import cn.zjh.base.constants.BaseConstants;
import cn.zjh.base.exception.BusinessException;
import cn.zjh.user.service.service.ILoginService;
import cn.zjh.base.utils.*;
import cn.zjh.base.vo.LoginVo;
import cn.zjh.base.vo.WechatVo;
import cn.zjh.user.domain.Logininfo;
import cn.zjh.user.domain.User;
import cn.zjh.user.domain.Wxuser;
import cn.zjh.user.mapper.LogininfoMapper;
import cn.zjh.user.mapper.UserMapper;
import cn.zjh.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
* @Description: 登录业务层实现类
* @Author: Mr.Zhang
* @Version: 1.0
* @Date:  2022/7/9 17:57
*/

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private UserMapper userMapper;


    @Autowired
    private RedisTemplate redisTemplate;


    /**
    * @Title: account
    * @Description: 前台账号登录
    * @Author: Mr.Zhang
    * @Version: 1.0
    * @Date:  2022/7/9 17:57
    * @Parameters:
    * @Return
    */
    @Override
    public HashMap<String, Object> account(LoginVo vo) {

        String username = vo.getUsername();
        String password = vo.getPassword();
        String type = vo.getType();
        //判空校验
        if (StringUtils.isEmpty(username)
                ||StringUtils.isEmpty(password)
                ||StringUtils.isEmpty(type)){
            throw new BusinessException("参数不能为空，请核对后输入必要参数！");
        }

        //根据账号查询loginInFo，username phone email账号此三种都算
        Logininfo logininfo = logininfoMapper.loadByUsernameAndType(username,type);

        if (logininfo == null){
            throw new BusinessException("账号密码错误，请重新输入！");
        }

        //生成UUID作为token并存入Redis设置过期时间为30分钟
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);

        //将用户敏感信息置空
        logininfo.setSalt("");
        logininfo.setPassword("");

        //将token/logininfo存入map中并返回map
        HashMap<String,Object> map = new HashMap<>();
        map.put("token",token);
        map.put("logininfo",logininfo);

        return map;
    }




    /**
    * @Title: wechat
    * @Description: 微信扫码登录
    * @Author: Mr.Zhang
    * @Version: 1.0
    * @Date:  2022/7/10 18:49
    * @Parameters:
    * @Return
    */
    @Override
    public AjaxResult wechat(WechatVo vo) {

        String code = vo.getCode();

        //判空校验
        if (StringUtils.isEmpty(code)){
            throw new BusinessException("参数不能为空！请重新输入！");
        }

        //替换掉原来的APPID和SECRET值，获取请求地址
        String tokenUrl = BaseConstants.WeCharConstant.TOKEN_URL
                .replace("APPID",BaseConstants.WeCharConstant.APPID)
                .replace("SECRET",BaseConstants.WeCharConstant.SECRET)
                .replace("CODE",code);

        //根据地址发起请求获取json格式的字符串
        String jsonStr = HttpUtil.httpGet(tokenUrl);

        //将json字符串转换为json对象
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        String accessToken = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");

        //根据获取的openid查询wxUser表数据
        Wxuser wxuser = wxuserMapper.loadByOpenId(openId);
        //判断微信用户是否存在,如果存在直接免密登录
        if (wxuser != null && wxuser.getUserId() != null){
            //根据wxuser中的userid查询logininfo数据
            Logininfo logininfo = logininfoMapper.loadByUserId(wxuser.getUserId());
            //生成UUID作为token并存入Redis设置过期时间为30分钟
            String token = UUID.randomUUID().toString();

            redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);

            //将用户敏感信息置空
            logininfo.setSalt("");
            logininfo.setPassword("");

            //将token/logininfo存入map中并返回map
            HashMap<String,Object> map = new HashMap<>();
            map.put("token",token);
            map.put("logininfo",logininfo);
            //返回map
            return AjaxResult.me().setResultObj(map);
        }
        //如果不存在，就传递access_token&openId到页面，并且success=false&message=nobinder
        StringBuilder paramStr = new StringBuilder()
                .append("?accessToken=")
                .append(accessToken)
                .append("&openId=")
                .append(openId);
        return AjaxResult.me().setSuccess(false).setMessage("nobinder").setResultObj(paramStr);
    }


    /**
    * @Title: binder
    * @Description: 微信登录绑定
    * @Author: Mr.Zhang
    * @Version: 1.0
    * @Date:  2022/7/10 22:02
    * @Parameters:
    * @Return
    */

    @Override
    public HashMap<String, Object> binder(WechatVo vo) {
        //非空校验
        String phone = vo.getPhone();
        String openId = vo.getOpenId();
        String verifyCode = vo.getVerifyCode();
        String accessToken = vo.getAccessToken();
        if (StringUtils.isEmpty(phone)
                ||StringUtils.isEmpty(openId)
                ||StringUtils.isEmpty(verifyCode)
                ||StringUtils.isEmpty(accessToken)) {
            throw new BusinessException("参数不能为空！");
        }

        //手机验证码校验
        String phoneCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_PREFIX+phone;
        Object phoneCodeRides = redisTemplate.opsForValue().get(phoneCodeKey);
        String phoneCode = phoneCodeRides.toString().split(":")[1];
        //判断验证码是否正确
        if (!phoneCode.equals(verifyCode)){
            throw  new BusinessException("验证码不正确，请重新输入！");
        }

        //根据手机号查询用户是否存在
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo = null;

        if (user == null){ //如果用户不存在,初始话user/logininfo并保存
            user = smsCodeDto2User(phone);
            logininfo = user2Logininfo(user);
            logininfoMapper.save(logininfo);
            user.setLogininfoId(logininfo.getId());
            userMapper.save(user);

        } else{//如果存在：就查询logininfo表直接登录
            Logininfo logininfo1 = logininfoMapper.loadByUserId(user.getId());
        }

        //根据前端传递的accessToken&openId查询微信用户基本信息
        String wxUserUrl = BaseConstants.WeCharConstant.WXUSER_URL
                .replace("ACCESS_TOKEN",accessToken)
                .replace("OPENID",openId);
        String wxUserStr = HttpUtil.httpGet(wxUserUrl);
        //将字符串对象转换为指定wxuser对象
        Wxuser wxuser = JSONObject.parseObject(wxUserStr, Wxuser.class);
        //保存wxUser对象，并且需要设置userId字段为user对象的主键
        wxuser.setUserId(user.getId());
        //保存到wxuser表中
        wxuserMapper.save(wxuser);
        //生成UUID作为token并存入Redis设置过期时间为30分钟
        String token = UUID.randomUUID().toString();

        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);

        //将用户敏感信息置空
        logininfo.setSalt("");
        logininfo.setPassword("");

        //将token/logininfo存入map中并返回map
        HashMap<String,Object> map = new HashMap<>();
        map.put("token",token);
        map.put("logininfo",logininfo);

        return map;
    }


    /**
     * 初始化User对象
     * @param phone
     * @return
     */
    private User smsCodeDto2User(String phone){
        User user = new User();
        //电话/用户名
        user.setPhone(phone);
        user.setUsername(phone);
        //密码
        String StrPwd = "123456";
        SmsUtils.sendCode(phone,"亲爱的用户，您的初始密码为："+StrPwd+"请尽快修改");

        //设置盐值/密码
        String salt = StrUtils.getComplexRandomString(32);
        String password = MD5Utils.encrypByMd5(StrPwd + salt);
        user.setSalt(salt);
        user.setPassword(password);
        return user;
    }


    /**
     * 初始化Logininfo对象
     * @param user
     * @return
     */
    private Logininfo user2Logininfo(User user){
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1);
        return logininfo;
    }



}
